﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace SuperKit
{
    /*
     * 压缩视频，就是一个ffmpeg的包装。
     * 将主目录底下的项目
     */
    class MakeVideo : MediaExecutor {

        private int thread;
        private List<FileInfo> files;
        private FileContainer container;
        private const string MAKE_DIR = "(_MAKE)";
        private SimpleThreadExecutor<FileInfo> exe;

        public MakeVideo(ArgReader arg, IExecutorOwner form, string fpath) : base(arg, form, fpath) {
            thread = Cfg.VideoMakeThread;
            container = new FileContainer(MAKE_DIR, new DirectoryInfo(FilePath), arg.TargetDir);
        }


        public override void Execute() {
            base.Execute();

            DirectoryInfo info = new DirectoryInfo(FilePath);
            files = Kit.GetFilteredFiles(Kit.GetAllFiles(null, info), Kit.MEDIA_EXT);            

            exe = new SimpleThreadExecutor<FileInfo>(files, thread);
            index = 0;
            exe.Start(OnProcess, End);
        }

        private int index;
        private void OnProcess(FileInfo item) {            
            SetStatus($"开始({exe.GetProcessString()})：{item.Name}");

            DateTime date = DateTime.Now;

            if (!Kit.IsFileType(item, Kit.MEDIA_EXT)) {
                return;
            }
            // 安全性检查，如果有限定的目录，则跳过
            if (item.FullName.Contains(MAKE_DIR)) {
                return;
            }

            string path = container.GetPath(item);
            if (!Kit.IsEmpty(ext)) {
                path = Kit.ChangeExtension(path, ext);
            }

            string cmd = $" -i \"{item.FullName}\" {SizeStr} {ByteStr} -y \"{path}\"";
            if (gpu) {
                cmd = $" -hwaccel_output_format cuda -i \"{item.FullName}\" {SizeStr} {ByteStr} -y  -vcodec h264_nvenc \"{path}\"";
            }

            ExecuteFFMpeg(index, cmd, item);

            Flush($"完成({exe.GetFinishString(true)}): {Path.GetFileName(path)}, 用时:{Kit.GetPassTime(date)}");
        }




        private void ExecuteFFMpeg(int fileIndex, string cmd, FileInfo item) {
            // 进入这个执行阶段，就可以换了。
            index++;

            string timeStr = RemoveMillisecond(SafelizeMovie.GetMovieTime(item.FullName));
            int timeSecond = TimeToSecond(timeStr);
            float maxProgess = 0f;

            Process p = new Process();
            p.StartInfo.FileName = ConfigReader.Instance.FFMpegExe;
            p.StartInfo.Arguments = cmd;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;

            p.ErrorDataReceived += new System.Diagnostics.DataReceivedEventHandler((SenderObject, EventArgs) => {
                string message = EventArgs.Data;
                string currentTime = RemoveMillisecond(PickTime(message));
                int currentSecond = TimeToSecond(currentTime);
                float process = currentSecond * 100.0f / timeSecond;
                if (Kit.IsEmpty(message) && maxProgess > 95f) {
                    process = 100f;
                }
                maxProgess = Math.Max(process, maxProgess);
                SetLog(fileIndex, $"[{maxProgess:N1}%][{TrimTimeString(currentTime)}/{TrimTimeString(timeStr)}]{item.Name}");
                //Flush(message);
            });



            p.Start();
            p.BeginErrorReadLine();
            p.WaitForExit();
            p.Close();
        }

        public const string EMPTY_TIME = "00:00:00.00";
        public static string PickTime(string message) {
            if (message == null) {
                return EMPTY_TIME;
            }
            int start = message.IndexOf("time=");
            if (start == -1) {
                return EMPTY_TIME;
            }
            int end = message.IndexOf(" ", start);
            return message.Substring(start + 5, end - (start + 5));
        }

        public static string RemoveMillisecond(string timeStr) {
            int index = timeStr.IndexOf('.');
            if (index == -1) {
                return timeStr;
            }
            return timeStr.Substring(0, index);
        }

        public static string TrimTimeString(string timeStr) {
            int index = timeStr.IndexOf("00:0");
            if (index != -1) {
                return timeStr.Substring(4);
            }
            index = timeStr.IndexOf("00:");
            if (index != -1) {
                return timeStr.Substring(3);
            }
            return timeStr;
        }

        public static int TimeToSecond(string timeStr) {
            string[] splits = timeStr.Split(':');
            int hour = int.Parse(splits[0]);
            int minute = int.Parse(splits[1]);
            float second = float.Parse(splits[2]); // 最后一个项目是防止有毫秒，毫秒是用.22这样的格式。
            return hour * 3600 + minute * 60 + (int)second;
        }
    }
}
